package com.mkx.domain.service;

import com.mkx.domain.entity.User;
import com.mkx.domain.entity.TenantUser;
import com.mkx.domain.vo.Email;
import com.mkx.domain.vo.PhoneNumber;
import com.mkx.domain.vo.Password;

import java.time.LocalDateTime;
import java.util.UUID;

/**
 * 用户领域服务
 * 封装跨实体的用户相关业务逻辑
 */
public class UserDomainService {
    
    /**
     * 创建新用户
     * @param username 用户名
     * @param plainPassword 明文密码
     * @param emailAddress 邮箱地址
     * @param phoneNumber 手机号
     * @return 创建的用户实体
     */
    public User createUser(String username, String plainPassword, String emailAddress, String phoneNumber) {
        // 验证用户名
        validateUsername(username);
        
        // 创建密码对象（自动加密）
        Password password = Password.create(plainPassword);
        
        // 验证并创建邮箱对象
        Email email = new Email(emailAddress);
        
        // 验证并创建手机号对象
        PhoneNumber phone = new PhoneNumber(phoneNumber);
        
        // 创建用户实体
        return new User(
                UUID.randomUUID().toString(),
                username,
                password.getHash() + ":" + password.getSalt(), // 存储格式: hash:salt
                email.getAddress(),
                phone.getNumber(),
                LocalDateTime.now(),
                LocalDateTime.now()
        );
    }
    
    /**
     * 验证用户密码
     * @param user 用户实体
     * @param plainPassword 待验证的明文密码
     * @return 是否验证通过
     */
    public boolean validatePassword(User user, String plainPassword) {
        // 从用户存储的密码中提取hash和salt
        String storedPassword = user.getPassword();
        if (storedPassword == null || !storedPassword.contains(":")) {
            return false;
        }
        
        String[] parts = storedPassword.split(":");
        if (parts.length != 2) {
            return false;
        }
        
        String hash = parts[0];
        String salt = parts[1];
        
        // 重建密码对象并验证
        Password password = Password.fromExisting(hash, salt);
        return password.matches(plainPassword);
    }
    
    /**
     * 更改用户密码
     * @param user 用户实体
     * @param oldPassword 旧密码
     * @param newPassword 新密码
     * @throws IllegalArgumentException 当旧密码验证失败时抛出
     */
    public void changePassword(User user, String oldPassword, String newPassword) {
        // 验证旧密码
        if (!validatePassword(user, oldPassword)) {
            throw new IllegalArgumentException("旧密码错误");
        }
        
        // 创建新密码并更新
        Password password = Password.create(newPassword);
        user.changePassword(password.getHash() + ":" + password.getSalt());
    }
    
    /**
     * 在租户中创建用户关联
     * @param tenantId 租户ID
     * @param userId 用户ID
     * @param roleId 角色ID
     * @return 租户用户实体
     */
    public TenantUser createTenantUser(String tenantId, String userId, String roleId) {
        // 验证参数
        validateId(tenantId, "租户ID");
        validateId(userId, "用户ID");
        validateId(roleId, "角色ID");
        
        return new TenantUser(
                UUID.randomUUID().toString(),
                tenantId,
                userId,
                roleId,
                LocalDateTime.now(),
                LocalDateTime.now()
        );
    }
    
    /**
     * 验证用户名
     */
    private void validateUsername(String username) {
        if (username == null || username.trim().isEmpty()) {
            throw new IllegalArgumentException("用户名不能为空");
        }
        if (username.length() < 3 || username.length() > 20) {
            throw new IllegalArgumentException("用户名长度必须在3-20个字符之间");
        }
        if (!username.matches("^[a-zA-Z0-9_\\u4e00-\\u9fa5]+$")) {
            throw new IllegalArgumentException("用户名只能包含字母、数字、下划线和中文");
        }
    }
    
    /**
     * 验证ID格式
     */
    private void validateId(String id, String idType) {
        if (id == null || id.trim().isEmpty()) {
            throw new IllegalArgumentException(idType + "不能为空");
        }
        try {
            // 尝试解析为UUID，验证格式
            UUID.fromString(id);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException(idType + "格式无效");
        }
    }
}